diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index c1d74211c..f1589da51 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -10,16 +10,7 @@ class SessionsController < Clearance::SessionsController def create account_or_nil = authenticate(params) - - sign_in(account_or_nil) do |status| - if status.success? - reset_auth_fail_count - redirect_back_or url_after_create - else - increment_auth_fail_count - sign_in_failure(status.failure_message) - end - end + sign_in(account_or_nil) { |status| handle_sign_in_result(status) } end def health @@ -28,6 +19,26 @@ def health private + def handle_sign_in_result(status) + if status.success? + set_remember_me_cookie + reset_auth_fail_count + redirect_back_or url_after_create + else + increment_auth_fail_count + sign_in_failure(status.failure_message) + end + end + + def set_remember_me_cookie + checked = params.dig(:login, :remember_me) == '1' + cookies[:remember_me] = { + httponly: true, secure: Clearance.configuration.secure_cookie, + same_site: :lax, path: '/', value: checked ? '1' : '', + expires: checked ? REMEMBER_ME_DURATION.from_now.utc : 1.day.ago.utc + } + end + def failed_login_thrice? account.auth_fail_count >= 3 end diff --git a/config/initializers/clearance.rb b/config/initializers/clearance.rb index 732b35493..c5dcd23cc 100644 --- a/config/initializers/clearance.rb +++ b/config/initializers/clearance.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +REMEMBER_ME_DURATION = 30.days + Clearance.configure do |config| config.routes = false config.mailer_sender = 'mailer@openhub.net' @@ -9,4 +11,7 @@ config.rotate_csrf_on_sign_in = true config.sign_in_guards = [Account::DisabledGuard] config.user_model = Account + config.cookie_expiration = lambda { |cookies| + cookies[:remember_me] == '1' ? REMEMBER_ME_DURATION.from_now.utc : nil + } end diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb index 208f9fa05..ac2279028 100644 --- a/test/controllers/sessions_controller_test.rb +++ b/test/controllers/sessions_controller_test.rb @@ -19,6 +19,25 @@ class SessionsControllerTest < ActionController::TestCase post :create, params: { login: { login: account.login, password: password } } _(Account.find(account.id).auth_fail_count).must_equal 0 end + + it 'must set remember_me helper cookie when checkbox is checked' do + post :create, params: { login: { login: account.login, password: password, remember_me: '1' } } + cookie_headers = Array(response.headers['Set-Cookie']) + remember_me_header = cookie_headers.find { |h| h.include?('remember_me=') } + _(remember_me_header).wont_be_nil + assert remember_me_header.include?('remember_me=1'), 'Cookie value should be 1' + assert remember_me_header.include?('expires=') || remember_me_header.include?('Max-Age='), + 'Cookie should have expiration set' + end + + it 'must delete remember_me helper cookie when checkbox is not checked' do + post :create, params: { login: { login: account.login, password: password, remember_me: '0' } } + cookie_headers = Array(response.headers['Set-Cookie']) + remember_me_header = cookie_headers.find { |h| h.include?('remember_me=') } + assert remember_me_header, 'remember_me cookie should be sent in response' + assert remember_me_header.include?('expires=') || remember_me_header.include?('Max-Age=0'), + 'Unchecked remember_me should be deleted with past expiry' + end end describe 'failure' do