Permalink
Browse files

Bring rememberable back.

  • Loading branch information...
1 parent f46d1b1 commit 2afad49a966a14f8f6bae6619610bc4daf91ba31 @josevalim josevalim committed Jan 14, 2010
View
@@ -27,8 +27,8 @@ module Orm
autoload :MongoMapper, 'devise/orm/mongo_mapper'
end
- ALL = [:authenticatable, :activatable, :confirmable, :recoverable, :rememberable,
- :timeoutable, :trackable, :validatable, :lockable]
+ ALL = [:authenticatable, :activatable, :confirmable, :recoverable,
+ :rememberable, :validatable, :trackable, :timeoutable, :lockable]
# Maps controller names to devise modules
CONTROLLERS = {
@@ -1,7 +1,4 @@
-# Each time the user is set we verify if it is still able to really sign in.
-# This is done by checking the time frame the user is able to sign in without
-# confirming it's account. If the user has not confirmed it's account during
-# this time frame, he/she will not able to sign in anymore.
+# Deny user access whenever his account is not active yet.
Warden::Manager.after_set_user do |record, warden, options|
if record && record.respond_to?(:active?) && !record.active?
scope = options[:scope]
@@ -0,0 +1,30 @@
+# After authenticate hook to verify if the user in the given scope asked to be
+# remembered while he does not sign out. Generates a new remember token for
+# that specific user and adds a cookie with this user info to sign in this user
+# automatically without asking for credentials. Refer to rememberable strategy
+# for more info.
+Warden::Manager.after_authentication do |record, warden, options|
+ scope = options[:scope]
+ remember_me = warden.params[scope].try(:fetch, :remember_me, nil)
+
+ if Devise::TRUE_VALUES.include?(remember_me) &&
+ warden.authenticated?(scope) && record.respond_to?(:remember_me!)
+ record.remember_me!
+
+ warden.response.set_cookie "remember_#{scope}_token", {
+ :value => record.class.serialize_into_cookie(record),
+ :expires => record.remember_expires_at,
+ :path => "/"
+ }
+ end
+end
+
+# Before logout hook to forget the user in the given scope, only if rememberable
+# is activated for this scope. Also clear remember token to ensure the user
+# won't be remembered again.
+Warden::Manager.before_logout do |record, warden, scope|
+ if record.respond_to?(:forget_me!)
+ record.forget_me!
+ warden.response.delete_cookie "remember_#{scope}_token"
+ end
+end
@@ -5,12 +5,14 @@
# verify timeout in the following request.
Warden::Manager.after_set_user do |record, warden, options|
scope = options[:scope]
- if record && record.respond_to?(:timeout?) && warden.authenticated?(scope)
+ if record && record.respond_to?(:timedout?) && warden.authenticated?(scope)
last_request_at = warden.session(scope)['last_request_at']
- if record.timeout?(last_request_at)
+
+ if record.timedout?(last_request_at)
warden.logout(scope)
throw :warden, :scope => scope, :message => :timeout
end
+
warden.session(scope)['last_request_at'] = Time.now.utc
end
end
@@ -1,3 +1,6 @@
+require 'devise/strategies/rememberable'
+require 'devise/hooks/rememberable'
+
module Devise
module Models
# Rememberable manages generating and clearing token for remember the user
@@ -16,7 +16,7 @@ def self.included(base)
end
# Checks whether the user session has expired based on configured time.
- def timeout?(last_access)
+ def timedout?(last_access)
last_access && last_access <= self.class.timeout_in.ago
end
@@ -1,12 +1,6 @@
-# Taken from RailsWarden, thanks to Hassox. http://github.com/hassox/rails_warden
module Warden::Mixins::Common
def request
- return @request if @request
- if env['action_controller.rescue.request']
- @request = env['action_controller.rescue.request']
- else
- Rack::Request.new(env)
- end
+ @request ||= env['action_controller.rescue.request']
end
def reset_session!
@@ -15,22 +9,15 @@ def reset_session!
end
def response
- return @response if @response
- if env['action_controller.rescue.response']
- @response = env['action_controller.rescue.response']
- else
- Rack::Response.new(env)
- end
+ @response ||= env['action_controller.rescue.response']
end
end
class Warden::SessionSerializer
- # Hook to serialize user into session. Overwrite if you want.
def serialize(record)
[record.class, record.id]
end
- # Hook to serialize user from session. Overwrite if you want.
def deserialize(keys)
klass, id = keys
klass.find(:first, :conditions => { :id => id })
@@ -4,9 +4,7 @@ module Devise
module Strategies
# Default strategy for signing in a user, based on his email and password.
# Redirects to sign_in page if it's not authenticated
- class Authenticatable < Warden::Strategies::Base
- include Devise::Strategies::Base
-
+ class Authenticatable < Base
def valid?
super && params[scope] && params[scope][:password].present?
end
@@ -1,7 +1,7 @@
module Devise
module Strategies
# Base strategy for Devise. Responsible for verifying correct scope and mapping.
- module Base
+ class Base < ::Warden::Strategies::Base
# Validate strategy. By default will raise an error if no scope or an
# invalid mapping is found.
def valid?
@@ -0,0 +1,37 @@
+require 'devise/strategies/base'
+
+module Devise
+ module Strategies
+ # Remember the user through the remember token. This strategy is responsible
+ # to verify whether there is a cookie with the remember token, and to
+ # recreate the user from this cookie if it exists. Must be called *before*
+ # authenticatable.
+ class Rememberable < Devise::Strategies::Base
+
+ # A valid strategy for rememberable needs a remember token in the cookies.
+ def valid?
+ super && remember_me_cookie.present?
+ end
+
+ # To authenticate a user we deserialize the cookie and attempt finding
+ # the record in the database. If the attempt fails, we pass to another
+ # strategy handle the authentication.
+ def authenticate!
+ if resource = mapping.to.serialize_from_cookie(remember_me_cookie)
+ success!(resource)
+ else
+ pass
+ end
+ end
+
+ private
+
+ # Accessor for remember cookie
+ def remember_me_cookie
+ @remember_me_cookie ||= request.cookies["remember_#{mapping.name}_token"]
+ end
+ end
+ end
+end
+
+Warden::Strategies.add(:rememberable, Devise::Strategies::Rememberable)
@@ -1,63 +1,63 @@
-# require 'test/test_helper'
-#
-# class RememberMeTest < ActionController::IntegrationTest
-#
-# def create_user_and_remember(add_to_token='')
-# Devise.remember_for = 1
-# user = create_user
-# user.remember_me!
-# cookies['warden.user.user.key'] = User.serialize_into_cookie(user) + add_to_token
-# user
-# end
-#
-# test 'do not remember the user if he has not checked remember me option' do
-# user = sign_in_as_user
-# assert_nil user.reload.remember_token
-# end
-#
-# test 'generate remember token after sign in' do
-# user = sign_in_as_user :remember_me => true
-# assert_not_nil user.reload.remember_token
-# end
-#
-# test 'remember the user before sign in' do
-# user = create_user_and_remember
-# get users_path
-# assert_response :success
-# assert warden.authenticated?(:user)
-# assert warden.user(:user) == user
-# end
-#
-# test 'do not remember with invalid token' do
-# user = create_user_and_remember('add')
-# get users_path
-# assert_response :success
-# assert_not warden.authenticated?(:user)
-# end
-#
-# test 'do not remember with token expired' do
-# user = create_user_and_remember
-# Devise.remember_for = 0
-# get users_path
-# assert_response :success
-# assert_not warden.authenticated?(:user)
-# end
-#
-# test 'forget the user before sign out' do
-# user = create_user_and_remember
-# get users_path
-# assert warden.authenticated?(:user)
-# get destroy_user_session_path
-# assert_not warden.authenticated?(:user)
-# assert_nil user.reload.remember_token
-# end
-#
-# test 'do not remember the user anymore after forget' do
-# user = create_user_and_remember
-# get users_path
-# assert warden.authenticated?(:user)
-# get destroy_user_session_path
-# get users_path
-# assert_not warden.authenticated?(:user)
-# end
-# end
+require 'test/test_helper'
+
+class RememberMeTest < ActionController::IntegrationTest
+
+ def create_user_and_remember(add_to_token='')
+ Devise.remember_for = 1
+ user = create_user
+ user.remember_me!
+ cookies['remember_user_token'] = User.serialize_into_cookie(user) + add_to_token
+ user
+ end
+
+ test 'do not remember the user if he has not checked remember me option' do
+ user = sign_in_as_user
+ assert_nil user.reload.remember_token
+ end
+
+ test 'generate remember token after sign in' do
+ user = sign_in_as_user :remember_me => true
+ assert_not_nil user.reload.remember_token
+ end
+
+ test 'remember the user before sign in' do
+ user = create_user_and_remember
+ get users_path
+ assert_response :success
+ assert warden.authenticated?(:user)
+ assert warden.user(:user) == user
+ end
+
+ test 'do not remember with invalid token' do
+ user = create_user_and_remember('add')
+ get users_path
+ assert_response :success
+ assert_not warden.authenticated?(:user)
+ end
+
+ test 'do not remember with token expired' do
+ user = create_user_and_remember
+ Devise.remember_for = 0
+ get users_path
+ assert_response :success
+ assert_not warden.authenticated?(:user)
+ end
+
+ test 'forget the user before sign out' do
+ user = create_user_and_remember
+ get users_path
+ assert warden.authenticated?(:user)
+ get destroy_user_session_path
+ assert_not warden.authenticated?(:user)
+ assert_nil user.reload.remember_token
+ end
+
+ test 'do not remember the user anymore after forget' do
+ user = create_user_and_remember
+ get users_path
+ assert warden.authenticated?(:user)
+ get destroy_user_session_path
+ get users_path
+ assert_not warden.authenticated?(:user)
+ end
+end
@@ -3,26 +3,26 @@
class TimeoutableTest < ActiveSupport::TestCase
test 'should be expired' do
- assert new_user.timeout?(31.minutes.ago)
+ assert new_user.timedout?(31.minutes.ago)
end
test 'should not be expired' do
- assert_not new_user.timeout?(29.minutes.ago)
+ assert_not new_user.timedout?(29.minutes.ago)
end
test 'should not be expired when params is nil' do
- assert_not new_user.timeout?(nil)
+ assert_not new_user.timedout?(nil)
end
test 'fallback to Devise config option' do
swap Devise, :timeout_in => 1.minute do
user = new_user
- assert user.timeout?(2.minutes.ago)
- assert_not user.timeout?(30.seconds.ago)
+ assert user.timedout?(2.minutes.ago)
+ assert_not user.timedout?(30.seconds.ago)
Devise.timeout_in = 5.minutes
- assert_not user.timeout?(2.minutes.ago)
- assert user.timeout?(6.minutes.ago)
+ assert_not user.timedout?(2.minutes.ago)
+ assert user.timedout?(6.minutes.ago)
end
end
end

0 comments on commit 2afad49

Please sign in to comment.