diff --git a/lib/generators/sorcery/templates/initializer.rb b/lib/generators/sorcery/templates/initializer.rb index 22e0f441..a8a48296 100644 --- a/lib/generators/sorcery/templates/initializer.rb +++ b/lib/generators/sorcery/templates/initializer.rb @@ -26,6 +26,11 @@ # # config.cookie_domain = + # Set name of the remember_me cookie + # Default: `:remember_me_token` + # + # config.remember_me_cookie_name = + # Allow the remember_me cookie to be set through AJAX # Default: `true` # diff --git a/lib/sorcery/controller/submodules/remember_me.rb b/lib/sorcery/controller/submodules/remember_me.rb index 57af975d..e3325861 100644 --- a/lib/sorcery/controller/submodules/remember_me.rb +++ b/lib/sorcery/controller/submodules/remember_me.rb @@ -10,9 +10,12 @@ def self.included(base) base.send(:include, InstanceMethods) Config.module_eval do class << self + attr_accessor :remember_me_cookie_name attr_accessor :remember_me_httponly + def merge_remember_me_defaults! - @defaults.merge!(:@remember_me_httponly => true) + @defaults.merge!(:@remember_me_cookie_name => :remember_me_token, + :@remember_me_httponly => true) end end merge_remember_me_defaults! @@ -36,13 +39,13 @@ def remember_me! # Clears the cookie, and depending on the value of remember_me_token_persist_globally, may clear the token value. def forget_me! current_user.forget_me! - cookies.delete(:remember_me_token, domain: Config.cookie_domain) + cookies.delete(Config.remember_me_cookie_name.to_sym, domain: Config.cookie_domain) end # Clears the cookie, and clears the token value. def force_forget_me! current_user.force_forget_me! - cookies.delete(:remember_me_token, domain: Config.cookie_domain) + cookies.delete(Config.remember_me_cookie_name.to_sym, domain: Config.cookie_domain) end # Override. @@ -59,7 +62,7 @@ def auto_login(user, should_remember = false) # and logs the user in if found. # Runs as a login source. See 'current_user' method for how it is used. def login_from_cookie - user = cookies.signed[:remember_me_token] && user_class.sorcery_adapter.find_by_remember_me_token(cookies.signed[:remember_me_token]) if defined? cookies + user = cookies.signed[Config.remember_me_cookie_name.to_sym] && user_class.sorcery_adapter.find_by_remember_me_token(cookies.signed[Config.remember_me_cookie_name.to_sym]) if defined? cookies if user && user.has_remember_me_token? set_remember_me_cookie!(user) session[:user_id] = user.id.to_s @@ -71,7 +74,7 @@ def login_from_cookie end def set_remember_me_cookie!(user) - cookies.signed[:remember_me_token] = { + cookies.signed[Config.remember_me_cookie_name.to_sym] = { value: user.send(user.sorcery_config.remember_me_token_attribute_name), expires: user.send(user.sorcery_config.remember_me_token_expires_at_attribute_name), httponly: Config.remember_me_httponly, diff --git a/spec/controllers/controller_remember_me_spec.rb b/spec/controllers/controller_remember_me_spec.rb index 5358bfcb..c1ff02ae 100644 --- a/spec/controllers/controller_remember_me_spec.rb +++ b/spec/controllers/controller_remember_me_spec.rb @@ -31,6 +31,20 @@ expect(cookies.signed['remember_me_token']).to eq assigns[:current_user].remember_me_token end + it 'sets cookie on remember_me! with custom cookie name' do + sorcery_controller_property_set(:remember_me_cookie_name, :custom) + + expect(User).to receive(:authenticate).with('bla@bla.com', 'secret') { |&block| block.call(user, nil) } + expect(user).to receive(:remember_me!) + + post :test_login_with_remember, params: { email: 'bla@bla.com', password: 'secret' } + + expect(cookies.signed['custom']).to eq assigns[:current_user].remember_me_token + + # Reset property back to default so it won't interfere with other tests. + sorcery_controller_property_set(:remember_me_cookie_name, :remember_me_token) + end + it 'clears cookie on forget_me!' do cookies['remember_me_token'] = { value: 'asd54234dsfsd43534', expires: 3600 } get :test_logout @@ -58,6 +72,22 @@ expect(cookies.signed['remember_me_token']).to eq assigns[:user].remember_me_token end + it 'login(email,password,remember_me) logs user in and remembers with custom cookie name' do + sorcery_controller_property_set(:remember_me_cookie_name, :custom) + + expect(User).to receive(:authenticate).with('bla@bla.com', 'secret', '1') { |&block| block.call(user, nil) } + expect(user).to receive(:remember_me!) + expect(user).to receive(:remember_me_token).and_return('abracadabra').twice + + post :test_login_with_remember_in_login, params: { email: 'bla@bla.com', password: 'secret', remember: '1' } + + expect(cookies.signed['custom']).not_to be_nil + expect(cookies.signed['custom']).to eq assigns[:user].remember_me_token + + # Reset property back to default so it won't interfere with other tests. + sorcery_controller_property_set(:remember_me_cookie_name, :remember_me_token) + end + it 'logout also calls forget_me!' do session[:user_id] = user.id.to_s expect(User.sorcery_adapter).to receive(:find_by_id).with(user.id.to_s).and_return(user) @@ -68,6 +98,21 @@ expect(cookies['remember_me_token']).to be_nil end + it 'logout also calls forget_me! with custom cookie name' do + sorcery_controller_property_set(:remember_me_cookie_name, 'custom') + + session[:user_id] = user.id.to_s + expect(User.sorcery_adapter).to receive(:find_by_id).with(user.id.to_s).and_return(user) + expect(user).to receive(:remember_me!) + expect(user).to receive(:forget_me!) + get :test_logout_with_remember + + expect(cookies['custom']).to be_nil + + # Reset property back to default so it won't interfere with other tests. + sorcery_controller_property_set(:remember_me_cookie_name, :remember_me_token) + end + it 'logs user in from cookie' do session[:user_id] = user.id.to_s expect(User.sorcery_adapter).to receive(:find_by_id).with(user.id.to_s).and_return(user) @@ -90,6 +135,33 @@ expect(assigns[:current_user]).to eq user end + it 'logs user in from cookie with custom cookie name' do + sorcery_controller_property_set(:remember_me_cookie_name, :custom) + + session[:user_id] = user.id.to_s + expect(User.sorcery_adapter).to receive(:find_by_id).with(user.id.to_s).and_return(user) + expect(user).to receive(:remember_me!) + expect(user).to receive(:remember_me_token).and_return('token') + expect(user).to receive(:has_remember_me_token?) { true } + + subject.remember_me! + subject.instance_eval do + remove_instance_variable :@current_user + end + session[:user_id] = nil + + expect(User.sorcery_adapter).to receive(:find_by_remember_me_token).with('token').and_return(user) + + expect(subject).to receive(:after_remember_me!).with(user) + + get :test_login_from_cookie + + expect(assigns[:current_user]).to eq user + + # Reset property back to default so it won't interfere with other tests. + sorcery_controller_property_set(:remember_me_cookie_name, :remember_me_token) + end + it 'doest not remember_me! when not asked to, even if third parameter is used' do post :test_login_with_remember_in_login, params: { email: 'bla@bla.com', password: 'secret', remember: '0' }